﻿using Fleck;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SerialWebSocket
{
    public partial class NxinForm : Form
    {
        List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();
        //WebSocketServer server = new WebSocketServer("ws://0.0.0.0:8181", true);
        WebSocketServer server = new WebSocketServer("ws://0.0.0.0:8181", true);

        //XmlHelper helper = new XmlHelper(GetWorkDirectory() + "\\SerialConfig.xml");
        Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        private SerialPort sp = new SerialPort();
        bool isOpen = false; //
        bool isSetProperty = false; //属性设置标志
        bool isHex = false; //十六进制显示标志


        public NxinForm()
        {
            InitializeComponent();

        }
        private static string GetWorkDirectory()
        {
            try
            {
                return Path.GetDirectoryName(typeof(NxinForm).Assembly.Location);
            }
            catch
            {
                return Application.StartupPath;
            }
        }


        private void btnStartService_Click(object sender, EventArgs e)
        {
            FleckLog.Level = LogLevel.Debug;
            var msg = string.Empty;

            foreach (var socket in allSockets.ToList())
            {
                socket.Close();
            }

            server.Start(socket =>
            {
                socket.OnOpen = () =>
                {
                    this.BeginInvoke((EventHandler)
                      delegate
                      {
                          msg = "Open!";
                          tbxRecvData3.Text = "socket-btnStartService_Click" + msg + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                          allSockets.Add(socket);
                      });

                };
                socket.OnClose = () =>
                {
                    this.BeginInvoke((EventHandler)
                    delegate
                    {
                        msg = "Close!";
                        tbxRecvData3.Text = "socket-btnStartService_Click" + msg + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        allSockets.Remove(socket);
                    });
                };
                //socket.OnMessage = message =>
                //{
                //    this.BeginInvoke((EventHandler)
                //      delegate
                //      {
                //          tbxRecvData3.Text = "socket-btnStartService_Click" + message + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                //          //allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
                //      });
                //};
            });
            btnStartService.Enabled = false;
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            for (int i = 0; i < 10; i++)
            {
                cbxComPort.Items.Add("COM" + (i + 1).ToString());
            }
            cbxComPort.SelectedIndex = 3;   //设置串口初始值
            //列出常用的波特率表
            cbxBaudRate.Items.Add("1200");
            cbxBaudRate.Items.Add("2400");
            cbxBaudRate.Items.Add("4800");
            cbxBaudRate.Items.Add("9600");
            cbxBaudRate.Items.Add("19200");
            cbxBaudRate.Items.Add("38400");
            cbxBaudRate.SelectedIndex = 3;
            //列出停止位
            cbxStopBits.Items.Add("0");
            cbxStopBits.Items.Add("1");
            cbxStopBits.Items.Add("1.5");
            cbxStopBits.Items.Add("2");
            cbxStopBits.SelectedIndex = 1;
            //列出数据位
            cbxDataBits.Items.Add("8");
            cbxDataBits.Items.Add("7");
            cbxDataBits.Items.Add("6");
            cbxDataBits.Items.Add("5");
            cbxDataBits.SelectedIndex = 0;
            //列出奇偶校验位
            cbxParity.Items.Add("无");
            cbxParity.Items.Add("奇校验");
            cbxParity.Items.Add("偶校验");
            cbxParity.SelectedIndex = 0;
            //默认char显示
            rbnChar.Checked = true;

            btnStartService.Enabled = false;


            var PortName = config.AppSettings.Settings["PortName"].Value;//com
            var BrPort = config.AppSettings.Settings["BrPort"].Value;//波特率
            var DataBits = config.AppSettings.Settings["DataBits"].Value;//校验位
            var stopBits = config.AppSettings.Settings["StopBits"].Value;//停止位
            var ParityCheck = config.AppSettings.Settings["ParityCheck"].Value;//奇偶校验


            var Separator = config.AppSettings.Settings["Separator"].Value;//分割符
            var UnitLen = config.AppSettings.Settings["UnitLen"].Value;//数据长度
            var Start = config.AppSettings.Settings["Start"].Value;//小数点前起始位
            var End = config.AppSettings.Settings["End"].Value;//小数点前数据长度
            var DStart = config.AppSettings.Settings["DStart"].Value;//小数点后起始位
            var DEnd = config.AppSettings.Settings["DEnd"].Value;//小数点后数据长度
            var TInterval = config.AppSettings.Settings["TInterval"].Value;//小数点后数据长度
            var RunOK = config.AppSettings.Settings["RunOK"].Value;//开机启动       

            cbxComPort.SelectedIndex = cbxComPort.Items.IndexOf(PortName);
            cbxBaudRate.SelectedIndex = cbxBaudRate.Items.IndexOf(BrPort);
            cbxDataBits.SelectedIndex = cbxDataBits.Items.IndexOf(DataBits);
            cbxStopBits.SelectedIndex = cbxStopBits.Items.IndexOf(stopBits);
            cbxParity.SelectedIndex = cbxParity.Items.IndexOf(ParityCheck);

            txtSplit.Text = Separator;
            txtLength.Text = UnitLen;
            txtStart.Text = Start;
            txtEnd.Text = End;
            txtDStart.Text = DStart;
            txtDEnd.Text = DEnd;
            txtSleep.Text = TInterval;

            txtSplit2.Text = Separator;
            txtLength2.Text = UnitLen;
            txtStart2.Text = Start;
            txtEnd2.Text = End;
            txtDStart2.Text = DStart;
            txtDEnd2.Text = DEnd;
            txtSleep2.Text = TInterval;

            try { chekRunOK.Checked = bool.Parse(RunOK); }
            catch { chekRunOK.Checked = false; }


            btnOpenCom_Click(sender, e);
            btnStartService_Click(sender, e);
        }

        private void btnCheckCom_Click(object sender, EventArgs e)
        {
            var PortName = cbxComPort.Text.Trim();
            var BrPort = cbxBaudRate.Text.Trim();
            var DataBits = cbxDataBits.Text.Trim();
            var stopBits = cbxStopBits.Text.Trim();
            var ParityCheck = cbxParity.Text.Trim();

            var Separator = txtSplit.Text.Trim();
            var UnitLen = txtLength.Text.Trim();
            var Start = txtStart.Text.Trim();
            var End = txtEnd.Text.Trim();
            var DStart = txtDStart.Text.Trim();
            var DEnd = txtDEnd.Text.Trim();
            var TInterval = txtSleep.Text.Trim();

            config.AppSettings.Settings["PortName"].Value = PortName;//com
            config.AppSettings.Settings["BrPort"].Value = BrPort;//波特率
            config.AppSettings.Settings["DataBits"].Value = DataBits;//校验位
            config.AppSettings.Settings["StopBits"].Value = stopBits;//停止位
            config.AppSettings.Settings["ParityCheck"].Value = ParityCheck;//奇偶校验


            config.AppSettings.Settings["Separator"].Value = Separator;//分割符
            config.AppSettings.Settings["UnitLen"].Value = UnitLen;//数据长度
            config.AppSettings.Settings["Start"].Value = Start;//小数点前起始位
            config.AppSettings.Settings["End"].Value = End;//小数点前数据长度
            config.AppSettings.Settings["DStart"].Value = DStart;//小数点后起始位
            config.AppSettings.Settings["DEnd"].Value = DEnd;//小数点后数据长度
            config.AppSettings.Settings["TInterval"].Value = TInterval;//小数点后数据长度
            //一定要记得保存，写不带参数的config.Save()也可以
            config.Save(ConfigurationSaveMode.Modified);
            //刷新，否则程序读取的还是之前的值（可能已装入内存）
            ConfigurationManager.RefreshSection("appSettings");

        }

        //串口检测 界面初始化
        private bool CheckPortSetting() //检测串口是否初始化
        {
            if (cbxComPort.Text.Trim() == "") return false;
            if (cbxBaudRate.Text.Trim() == "") return false;
            if (cbxDataBits.Text.Trim() == "") return false;
            if (cbxParity.Text.Trim() == "") return false;
            if (cbxStopBits.Text.Trim() == "") return false;
            return true;
        }

        private void SetPortProperty() //
        {
            sp = new SerialPort();
            sp.PortName = cbxComPort.Text.Trim();  //设置串口名
            sp.BaudRate = Convert.ToInt32(cbxBaudRate.Text.Trim()); //设置串口波特率
            int f = (int)Convert.ToSingle(cbxStopBits.Text.Trim()) * 10; //设置停止位            
            switch (f)
            {
                case 0:
                    sp.StopBits = StopBits.None;
                    break;
                case 10:
                    sp.StopBits = StopBits.One;
                    break;
                case 15:
                    sp.StopBits = StopBits.OnePointFive;
                    break;
                case 20:
                    sp.StopBits = StopBits.Two;
                    break;
                default:
                    sp.StopBits = StopBits.None;
                    break;
            }
            sp.DataBits = Convert.ToInt16(cbxDataBits.Text.Trim()); //设置数据位
            string parityType = cbxParity.Text.Trim(); //设置奇偶校验
            switch (parityType)
            {
                case "无":
                    sp.Parity = Parity.None;
                    break;
                case "奇校验":
                    sp.Parity = Parity.Odd;
                    break;
                case "偶校验":
                    sp.Parity = Parity.Even;
                    break;
                default:
                    sp.Parity = Parity.None;
                    break;
            }
            sp.ReadTimeout = -1; //超时读取时间
            sp.RtsEnable = true; // 指示本设备准备好可接收数据
            //定义Data Received事件，当串口收到数据后出发事件
            sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
        }

        private void btnOpenCom_Click(object sender, EventArgs e)
        {
            if (isOpen == false)
            {
                if (!CheckPortSetting())  //检测串口设置
                {
                    MessageBox.Show("串口未设置", "错误提示");
                    return;
                }
                if (isSetProperty == false) // 检测
                {
                    SetPortProperty();
                    isSetProperty = true;
                }
                try //打开串口
                {
                    sp.Open();
                    isOpen = true;
                    btnOpenCom.Text = "关闭串口";
                    //串口打开后相关的串口设置按钮不再可选择
                    cbxBaudRate.Enabled = false;
                    cbxComPort.Enabled = false;
                    cbxDataBits.Enabled = false;
                    cbxParity.Enabled = false;
                    cbxStopBits.Enabled = false;
                    txtSleep.Enabled = false;



                    txtSplit.Enabled = false;
                    txtLength.Enabled = false;
                    txtStart.Enabled = false;
                    txtEnd.Enabled = false;
                    txtDStart.Enabled = false;
                    txtDEnd.Enabled = false;

                }
                catch (Exception)
                {   //失败后设置
                    isSetProperty = false;
                    isOpen = false;
                    MessageBox.Show("串口无效或已经被占用！", "错误提示");
                }
            }
            else
            {
                sp.Close();
                isOpen = false;
                isSetProperty = false;
                btnOpenCom.Text = "打开串口";
                //重置选择按钮有效
                cbxBaudRate.Enabled = true;
                cbxComPort.Enabled = true;
                cbxDataBits.Enabled = true;
                cbxParity.Enabled = true;
                cbxStopBits.Enabled = true;
                txtSleep.Enabled = true;
                // btnStartService.Enabled = false;   
                txtSplit.Enabled = true;
                txtLength.Enabled = true;
                txtStart.Enabled = true;
                txtEnd.Enabled = true;
                txtDStart.Enabled = true;
                txtDEnd.Enabled = true;
            }

        }
        long k = 0;
        private void sp_DataReceived(object sender, EventArgs e)
        {
            try
            {
                var Sleep = int.Parse(txtSleep.Text.Trim());
                System.Threading.Thread.Sleep(Sleep);  //延迟100ms等待接收完成数据

                //this.BeginInvoke((EventHandler)
                //    delegate
                //    {
                if (sp.IsOpen)
                {
                    if (isHex == false)
                    {
                        System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();// 显示汉字与字符
                        Byte[] readBytes = new Byte[sp.BytesToRead];
                        sp.Read(readBytes, 0, readBytes.Length);
                        string decodedString = utf8.GetString(readBytes);
                        tbxRecvData.Text = decodedString;
                        tbxRecvData3.AppendText("【" + (k++) + "】" + decodedString + "\n");
                        if (decodedString.Length > 5)
                            GetWeightOfPort(decodedString);
                    }
                    else
                    {
                        int i_InNum;//输入缓冲区中字节数
                        i_InNum = sp.BytesToRead;

                        Byte[] ReceivedData = new Byte[sp.BytesToRead];//创建接收字节数组
                        sp.Read(ReceivedData, 0, ReceivedData.Length);//读取接收的数据
                        String RecvDataText = null;

                        for (int i = 0; i < ReceivedData.Length; i++)
                        {
                            RecvDataText += (ReceivedData[i].ToString("X2") + " ");
                        }
                        tbxRecvData.Text += RecvDataText;
                    }
                }
                sp.DiscardInBuffer();
                //});
            }
            catch (Exception ex) { tbxRecvData3.Text = "socket-sp_DataReceived" + ex.Message + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); }
        }
        long i = 0;
        /// <summary>
        /// 返回串口读取的重量
        /// </summary>
        /// <param name="?"></param>
        /// <returns></returns>
        private void GetWeightOfPort(string weight)
        {
            var sendweight = "0.00";
            try
            {
                tbxRecvLen1.Text = weight.Length.ToString();
                int length = 0;
                int.TryParse(txtLength.Text, out length);

                var txtS = txtStart.Text.Trim();
                var txtE = txtEnd.Text.Trim();

                var txtSe = txtDStart.Text.Trim();
                var txtEe = txtDEnd.Text.Trim();
                var tempweight = weight.Substring(0, length);
                var temptempweight = weight.Split(new string[] { txtSplit.Text.Trim() }, StringSplitOptions.None);
                tempweight = temptempweight.Length > 1 ? temptempweight[1] : tempweight;

                int s = 0;
                int.TryParse(txtS, out s);
                int e = 0;
                int.TryParse(txtE, out e);
                int se = 0;
                int.TryParse(txtSe, out se);
                int ee = 0;
                int.TryParse(txtEe, out ee);

                if (se != 0 && ee != 0)
                {
                    sendweight = int.Parse(tempweight.Substring(s, e)).ToString() + "." + tempweight.Substring(se, ee);
                }
                else
                {
                    sendweight = int.Parse(tempweight.Substring(s, e)).ToString();
                }
            }
            catch (Exception ex) { 
                tbxRecvData3.Text = "【" + weight.Trim() + "】GetWeightOfPort-socket" + ex.Message + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                sendweight = "0.00";
            }

            foreach (var socket in allSockets.ToList())
            {
                if (socket.IsAvailable)
                {
                    socket.Send(sendweight);
                    txtConverter.Text = "[fs消息" + (i++) + "]:" + sendweight;
                }

            }
        }

        private void btnConverter_Click(object sender, EventArgs e)
        {

            string weight = tbxRecvData.Text.Trim();
            if (weight.Length > 5)
                GetWeightOfPort(weight);

        }



        #region 模拟数据区

        bool isImitate = false; //

        private void btnImitateTran_Click(object sender, EventArgs ev)
        {
            txtConverter2.Text = ImitateDate();
        }

        private void btnImitate_Click(object sender, EventArgs e)
        {

            if (!isImitate)
            {
                this.btnImitate.Text = "关闭模拟";
                isImitate = true;
                var TInterval = txtSleep2.Text.Trim();
                timer2.Interval = int.Parse(TInterval);
                timer2.Enabled = true;

            }
            else
            {
                this.btnImitate.Text = "开始模拟";
                isImitate = false;
                timer2.Enabled = false;

            }


        }

        private string ImitateDate()
        {
            var sendweight = "0.00";
            try
            {
                tbxRecvLen2.Text = tbxRecvData2.Text.Length.ToString();
                int length = 0;
                int.TryParse(txtLength2.Text, out length);

                var txtS = txtStart2.Text.Trim();
                var txtE = txtEnd2.Text.Trim();

                var txtSe = txtDStart2.Text.Trim();
                var txtEe = txtDEnd2.Text.Trim();

                var tempweight = tbxRecvData2.Text.Substring(0, length);

                var temptempweight = tbxRecvData2.Text.Split(new string[] { txtSplit2.Text.Trim() }, StringSplitOptions.None);

                tempweight = temptempweight.Length > 1 ? temptempweight[1] : tempweight;

                int s = 0;
                int.TryParse(txtS, out s);
                int e = 0;
                int.TryParse(txtE, out e);
                int se = 0;
                int.TryParse(txtSe, out se);
                int ee = 0;
                int.TryParse(txtEe, out ee);

                if (se != 0 && ee != 0)
                {
                    sendweight = int.Parse(tempweight.Substring(s, e)).ToString() + "." + tempweight.Substring(se, ee);
                }
                else
                {
                    sendweight = int.Parse(tempweight.Substring(s, e)).ToString();
                }
            }
            catch (Exception ex)
            {
                tbxRecvData3.Text = "socket-ImitateDate" + ex.Message + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                sendweight = ex.Message;
            }

            return sendweight;


        }
        long j = 0;
        private void timer2_Tick(object sender, EventArgs e)
        {
            var sendweight = ImitateDate();
            txtConverter2.Text = "[消息" + (j++) + "]:" + sendweight;
            foreach (var socket in allSockets.ToList())
            {
                socket.Send(sendweight);
            }
        }
        #endregion

        #region 系统设置区
        private void chekRunOK_Click(object sender, EventArgs e)
        {
            config.AppSettings.Settings["RunOK"].Value = chekRunOK.Checked.ToString();//小数点后数据长度     //一定要记得保存，写不带参数的config.Save()也可以
            config.Save(ConfigurationSaveMode.Modified);
            //刷新，否则程序读取的还是之前的值（可能已装入内存）
            ConfigurationManager.RefreshSection("appSettings");
            if (chekRunOK.Checked)
            {
                StartUp("1");
            }
            else
            {
                StartUp("0");
            }
        }

        /// <summary>  
        /// 修改程序在注册表中的键值  
        /// </summary>  
        /// <param name="flag">1:开机启动</param>  
        private void StartUp(string flag)
        {
            string path = Application.StartupPath;
            string keyName = path.Substring(path.LastIndexOf("\\") + 1);
            Microsoft.Win32.RegistryKey Rkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);

            if (flag.Equals("1"))
            {
                if (Rkey == null)
                {
                    Rkey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
                }
                Rkey.SetValue(keyName, path + @"\SerialWebSocket.exe");
            }
            else
            {
                if (Rkey != null)
                {
                    Rkey.DeleteValue(keyName, false);
                }
            }
        }


        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                //还原窗体显示    
                WindowState = FormWindowState.Normal;
                //激活窗体并给予它焦点
                this.Activate();
                //任务栏区显示图标
                this.ShowInTaskbar = true;
                //托盘区图标隐藏
                notifyIcon1.Visible = false;
            }

        }

        private void NxinForm_SizeChanged(object sender, EventArgs e)
        {
            //判断是否选择的是最小化按钮
            if (WindowState == FormWindowState.Minimized)
            {
                //隐藏任务栏区图标
                this.ShowInTaskbar = false;
                //图标显示在托盘区
                notifyIcon1.Visible = true;
            }
        }

        private void NxinForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MessageBox.Show("是否确认退出程序？", "退出", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
            {
                // 关闭所有的线程
                this.Dispose();
                this.Close();
            }
            else
            {
                e.Cancel = true;
            }
        }

        #endregion

        private void timer1_Tick(object sender, EventArgs e)
        {
            string weight = tbxRecvData.Text.Trim();

            if (weight.Length > 5)
            {
                GetWeightOfPort(weight);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (timer1.Enabled == true)
            {
                var TInterval = txtSleep.Text.Trim();
                timer1.Interval = int.Parse(TInterval);
                timer1.Enabled = false;
                this.button1.Text = "调试";
            }
            else
            {
                var TInterval = txtSleep.Text.Trim();
                timer1.Interval = int.Parse(TInterval);
                timer1.Enabled = true;
                this.button1.Text = "关闭调试";
            }

        }
    }
}
